using System;
using System.Net;
using System.Runtime.Remoting.Messaging;
using System.Threading;

namespace Kugar.Core.Communications.Transfer
{


    public interface ITransfer : IDisposable
    {
        Guid TransferID { get; }

        //int Send(byte[] sendStruct);

        //int Send(byte[] sendStruct, int offset, int count);

        //IAsyncResult BeginSend(byte[] data, AsyncCallback callback, object state);
        //IAsyncResult BeginSend(byte[] data, int offset, int count, AsyncCallback callback, object state);

        //int EndSend(IAsyncResult iar);

        //int EndSend(IAsyncResult iar,ref Exception error);

        bool SendAsync(TransferAsyncEventArgs e);

        bool ReceiveAsync(TransferAsyncEventArgs e);

        //IAsyncResult BeginReceive(byte[] buffer, AsyncCallback callback, object state);

        //IAsyncResult BeginReceive(byte[] buffer, int offset, int count, AsyncCallback callback, object state);

        //int EndReceive(IAsyncResult iar);

        //int EndReceive(IAsyncResult iar, ref Exception error);

        void Start();

        void Stop();

        void Close();

        bool IsStop { get; }

        int ReceiveBufferCount { set; get; }

        bool IsActivity { get; }

        event EventHandler<TransferAsyncEventArgs> BeforceSendData;

        event EventHandler<TransferAsyncEventArgs> AfterSendData;

        event EventHandler<TransferAsyncEventArgs> AfterReceiveData;

        event EventHandler<TransferClosedEventArgs> TransferClosed;

        event EventHandler TransferStop;
        event EventHandler TransferStart;
    }

    public interface INetTransfer : ITransfer
    {
        int LocalPort { get; }
        IPEndPoint RemotePoint { get; }
    }

    public abstract class TransferBase : MarshalByRefObject, ITransfer
    {
        protected bool _isDisposed = false;

        protected TransferBase()
        {
            TransferID = Guid.NewGuid();
        }

        public void Dispose()
        {
            this.Dispose(true);
        }

        public Guid TransferID { get; protected set; }

        public abstract bool SendAsync(TransferAsyncEventArgs e);
        public abstract bool ReceiveAsync(TransferAsyncEventArgs e);

        //public int Send(byte[] sendStruct)
        //{
        //    return Send(sendStruct, 0, sendStruct.Length);
        //}

        //public virtual int Send(byte[] sendStruct, int offset, int count)
        //{
        //    var auto = new AutoResetEvent(false);
        //    var sendedCount = 0;
        //    Exception error = null;

        //    var iar=BeginSend(sendStruct, offset, count, (ar) =>
        //                                                 {
        //                                                     Exception err = null;
        //                                                     sendedCount = this.EndSend(ar, ref err);
        //                                                     error = err;
        //                                                     auto.Set();
        //                                             }, null);



        //    if(!auto.WaitOne())
        //    {
        //        throw new TimeoutException();
        //    }

        //    if (error!=null)
        //    {
        //        throw error;
        //    }

        //    return sendedCount;
        //}

        //public IAsyncResult BeginSend(byte[] data, AsyncCallback callback, object state)
        //{
        //    return BeginSend(data, 0, data.Length, callback, state);
        //}

        //public abstract IAsyncResult BeginSend(byte[] data, int offset, int count, AsyncCallback callback, object state);

        //public int EndSend(IAsyncResult iar)
        //{
        //    Exception error = null;

        //    var i = EndSend(iar, ref error);

        //    if (error!=null)
        //    {
        //        throw error;
        //    }
        //    else
        //    {
        //        return i;
        //    }
        //}

        //public abstract int EndSend(IAsyncResult iar, ref Exception error);

        //public void SendAsync(byte[] sendStruct, EventHandler<DataAfterSendEventArgs> callback, object state)
        //{

        //    SendAsync(sendStruct, 0, sendStruct.Length, callback, state);

        //}

        //public virtual void SendAsync(byte[] sendStruct, int offset, int count, EventHandler<DataAfterSendEventArgs> callback, object state)
        //{
        //    if (IsStop)
        //    {
        //        return;
        //    }

        //    if (sendStruct != null && sendStruct.Length > 0)
        //    {
        //        var s = CodeSendData(sendStruct, offset, count);

        //        OnBeforceSendData(s,null);

        //        Exception error = null;
                
        //        SendDataAsync(s.Array, s.Offset, s.Count, (s1,e1)=>
        //                                                        {
        //                                                            try
        //                                                            {
        //                                                                if (callback!=null)
        //                                                                {
        //                                                                    e1.UserState = state;
        //                                                                    callback(this, e1);
        //                                                                }
                                                                        
        //                                                            }
        //                                                            catch (Exception)
        //                                                            {
                                                                        
        //                                                            }

        //                                                            //OnAfterSendData(sendStruct, e1.Error);
        //                                                        }, state);


        //    }
        //}

        public virtual void Start()
        {
            if (OnStart())
            {
                Events.EventHelper.Raise(TransferStart, this);
            }
        }

        public virtual void Stop()
        {
            if (OnStop())
            {
                Events.EventHelper.Raise(TransferStop, this);
            }
        }


        public virtual void Close()
        {
            OnClose();
            Events.EventHelper.Raise(TransferClosed, this, new TransferClosedEventArgs(this));
        }

        public abstract bool IsStop { get; }

        public abstract int ReceiveBufferCount { get; set; }

        public abstract bool IsActivity { get; }

        public event EventHandler<TransferAsyncEventArgs> BeforceSendData;
        public event EventHandler<TransferAsyncEventArgs> AfterSendData;
        public event EventHandler<TransferAsyncEventArgs> AfterReceiveData;
        public event EventHandler<TransferClosedEventArgs> TransferClosed;
        public event EventHandler TransferStop;
        public event EventHandler TransferStart;

        protected virtual void OnBeforceSendData(TransferAsyncEventArgs e)
        {
            if (BeforceSendData != null)
            {
                BeforceSendData(this, e);
                //Events.EventHelper.Raise(BeforceSendData, this, new DataSendEventArgs(this,new ArraySegment<byte>(buffer,offset,count), error, null));
            }
        }

        protected virtual void OnAfterSendData(TransferAsyncEventArgs e)
        {
            if (AfterSendData != null)
            {
                AfterSendData(this, e);
                //Events.EventHelper.RaiseAsync(AfterSendData, this, new DataAfterSendEventArgs(this, new ArraySegment<byte>(buffer,offset,count), sendCount, error, null));
            }
        }

        protected virtual void OnAfterReceiveData(TransferAsyncEventArgs e)
        {
            if (AfterReceiveData != null)
            {
                AfterReceiveData(this, e);
                //Events.EventHelper.RaiseAsync(AfterReceiveData, this, new DataReceiveEventArgs(new ArraySegment<byte>(buffer, offset, count), this, DateTime.Now, error));
            }
        }

        //protected abstract void SendDataAsync(byte[] sendStruct, int offset, int count, EventHandler<DataAfterSendEventArgs> callback, object state);

        //protected virtual ArraySegment<byte> CodeSendData(byte[] sendStruct, int offset, int count)
        //{
        //    return new ArraySegment<byte>(sendStruct, offset, count);
        //}

        protected virtual void Dispose(bool isDisposing)
        {
            if (!_isDisposed)
            {
                if (isDisposing)
                {
                    Close();
                }
            }
        }

        protected abstract void OnClose();

        protected abstract bool OnStart();

        protected abstract bool OnStop();

    }




    public class DataSendEventArgs : EventArgs
    {
        private ITransfer _transfer = null;

        public DataSendEventArgs(ITransfer transfer, ArraySegment<byte> sendedData)
            : this(transfer,sendedData, null, null)
        {

        }

        public DataSendEventArgs(ITransfer transfer, ArraySegment<byte> sendedData, Exception error, object userState)
        {
            SendedData = sendedData;
            Error = error;
            UserState = userState;
        }

        public Exception Error { set; get; }

        public bool HasError { get { return Error != null; } }

        public object UserState { set; get; }

        public ArraySegment<byte> SendedData;

        public ITransfer Transfer { get { return _transfer; } }
    }

    public class DataAfterSendEventArgs:DataSendEventArgs
    {
        private int _sendCount = 0;

        public DataAfterSendEventArgs(ITransfer transfer, ArraySegment<byte> sendedData, int sendCount)
            : this(transfer,sendedData, sendCount, null, null)
        {
        }

        public DataAfterSendEventArgs(ITransfer transfer, ArraySegment<byte> sendedData, int sendCount, Exception error, object userState)
            : base(transfer,sendedData, error, userState)
        {
            _sendCount = sendCount;
        }

        public int SendCount { get { return _sendCount; } }
    }

    public class DataReceiveEventArgs : EventArgs
    {
        public DataReceiveEventArgs(ArraySegment<byte> receiveData, ITransfer transfer)
            : this(receiveData, transfer, DateTime.Now, null)
        {

        }

        public DataReceiveEventArgs(ArraySegment<byte> receiveData, ITransfer transfer, DateTime receiveTime, Exception error)
        {
            ReceiveData = receiveData;
            Error = error;
            Transfer = transfer;
        }

        public Exception Error { set; get; }

        public bool HasError { get { return Error != null; } }

        public ArraySegment<byte> ReceiveData;

        public ITransfer Transfer { get; private set; }

    }

    public class TransferClosedEventArgs : EventArgs
    {
        public TransferClosedEventArgs(ITransfer transfer)
        {
            Transfer = transfer;
        }

        public ITransfer Transfer { get; private set; }
    }

    public class TransferClosingEventArgs : EventArgs
    {
        public TransferClosingEventArgs(ITransfer transfer)
        {
            Transfer = transfer;
        }

        public ITransfer Transfer { get; private set; }
    }
}